package com.blb.seckill.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.blb.seckill.config.RabbitMQConfig;
import com.blb.seckill.entity.SeckillCourse;
import com.blb.seckill.entity.SeckillOrder;
import com.blb.seckill.mapper.SeckillCourseMapper;
import com.blb.seckill.mapper.SeckillOrderMapper;
import com.blb.seckill.service.SeckillOrderService;
import com.blb.seckill.util.Constants;
import com.learn.eduapi.util.DateUtil;
import com.learn.eduapi.util.IdWorker;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class SeckillOrderServiceImpl extends ServiceImpl<SeckillOrderMapper, SeckillOrder> implements SeckillOrderService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private IdWorker idWorker;

    @Override
    public SeckillOrder addOrder(Long id, String username) {
        //防止用户恶意刷单
        String result = this.preventRepeatCommit(username, id);
        if ("fail".equals(result)){
            return null;
        }
        //防止重复下单
        SeckillOrder order = this.getOne(new QueryWrapper<SeckillOrder>().lambda().eq(SeckillOrder::getUserId, username).eq(SeckillOrder::getSeckillId, id));
        if(order != null){
            return null;
        }
        String time = DateUtil.getTodayString();
        //获得Redis中的课程
        SeckillCourse course = (SeckillCourse) redisTemplate.boundHashOps(Constants.COURSE_KEY + time).get(""+id);
        //获得Redis中该课程的库存
        Integer stock = (Integer) redisTemplate.opsForValue().get(Constants.COURSE_STOCK_KEY + id);
        if(stock == null || stock <= 0 || course == null){
            return null;
        }
        //扣减Redis中的库存
        Long newStock = redisTemplate.opsForValue().decrement(Constants.COURSE_STOCK_KEY + id);
        //如果库存为0，就删除Redis中的课程和库存
        if(newStock <= 0){
            redisTemplate.boundHashOps(Constants.COURSE_KEY + time).delete(""+id);
            redisTemplate.delete(Constants.COURSE_STOCK_KEY + id);
        }
        //创建订单，发送消息进行异步下单
        SeckillOrder seckillOrder = new SeckillOrder();
        seckillOrder.setId(idWorker.nextId());
        seckillOrder.setSeckillId(id);
        seckillOrder.setMoney(course.getCostPrice());
        seckillOrder.setUserId(username);
        seckillOrder.setPayTime(new Date());
        seckillOrder.setCreateTime(new Date());
        seckillOrder.setStatus("0");
        //发送消息
        sendMessage(JSON.toJSONString(seckillOrder),"", RabbitMQConfig.QUEUE_SECKILLORDER);
        return seckillOrder;
    }

    public void sendMessage(String message,String exchange,String routingKey){
        //设置消息唯一标识并存入缓存
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        redisTemplate.opsForValue().set(correlationData.getId(),message);
        //本次发送到相关元信息存入缓存，以备失败重发
        Map<String, String> map = new HashMap<>();
        map.put("exchange", exchange);
        map.put("routingKey", routingKey);
        map.put("sendMessage", message);
        redisTemplate.opsForHash().putAll(RabbitMQConfig.MESSAGE_CONFIRM+correlationData.getId(),map);
        //携带唯一标识发送消息
        rabbitTemplate.convertAndSend(exchange,routingKey,message,correlationData);
    }

    //防止重复提交
    private String preventRepeatCommit(String username,Long id) {
        String redisKey = "seckill_user_" + username+"_id_"+id;
        long count = redisTemplate.opsForValue().increment(redisKey, 1);
        if (count == 1){
            //设置有效期五分钟
            redisTemplate.expire(redisKey, 5, TimeUnit.MINUTES);
            return "success";
        }
        if (count>1){
            return "fail";
        }
        return "fail";
    }

    @Autowired
    private SeckillCourseMapper seckillCourseMapper;

    @Autowired
    private SeckillOrderMapper seckillOrderMapper;

    @Transactional
    @Override
    public boolean createOrder(SeckillOrder order) {
        SeckillCourse course = seckillCourseMapper.selectById(order.getSeckillId());
        if(course == null){
            return false;
        }
        if(course.getStockCount() <= 0){
            return false;
        }
        //更新库存
        course.setStockCount(course.getStockCount() - 1);
        seckillCourseMapper.updateById(course);
        //插入订单
        seckillOrderMapper.insert(order);
        return true;
    }
}
